package com.bocloud.cmp.driver.providers.os;

import java.util.Date;
import java.util.List;

import org.openstack4j.api.Builders;
import org.openstack4j.api.exceptions.ClientResponseException;
import org.openstack4j.model.common.ActionResponse;
import org.openstack4j.model.compute.Action;
import org.openstack4j.model.compute.RebootType;
import org.openstack4j.model.compute.Server;
import org.openstack4j.model.compute.ServerCreate;
import org.openstack4j.model.compute.ServerUpdateOptions;
import org.openstack4j.model.compute.VNCConsole;
import org.openstack4j.model.compute.VNCConsole.Type;
import org.openstack4j.model.compute.actions.LiveMigrateOptions;
import org.openstack4j.model.image.Image;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.bocloud.cmp.driver.convertor.BeanConvert;
import com.bocloud.cmp.driver.convertor.os.ConvertImage;
import com.bocloud.cmp.driver.convertor.os.ConvertServer;
import com.bocloud.cmp.driver.providers.ServerDriver;
import com.bocloud.cmp.model.ImageModel;
import com.bocloud.cmp.model.OSMigrateModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.common.model.BsmResult;
import com.google.common.collect.Lists;

/**
 * OpenStack虚拟机操作驱动
 * 
 * @author dmw
 *
 */
public class OSServerDriver extends OSDriver implements ServerDriver {

    private static Logger logger = LoggerFactory.getLogger(OSServerDriver.class);

    /**
     * 
     */
    public OSServerDriver() {
        super();
    }

    public OSServerDriver(String endpoint, String username, String password, String tenant, String domain,
            String project, Version version) {
        super(endpoint, username, password, tenant, domain, project, version);
    }

    @Override
    public BsmResult create(ServerModel server) {
        List<String> networks = Lists.newArrayList();
        Server result = null;
        if (StringUtils.hasLength(server.getNetworkId())) {
            String[] networkArray = server.getNetworkId().split(",");
            for (String net : networkArray) {
                networks.add(net.trim());
            }
        }
        try {
            ServerCreate serverCreate = Builders.server().name(server.getName()).flavor(server.getFlavorId())
                    .image(server.getImageId()).addSecurityGroup(server.getSecurityGroupId()).networks(networks)
                    .addPersonality("/etc/motd", "Welcome to the new VM! Restricted access only").build();
            if (!this.accessable()) {
                logger.error(this.getError());
                return new BsmResult(false, this.getError());
            }

            result = this.getClient().compute().servers().boot(serverCreate);
        } catch (ClientResponseException e) {
            logger.error("创建失败！", e);
            if (403 == e.getStatus()) {
                if (null != result) {
                    return new BsmResult(true, detail(result.getId()).getData(), "创建失败");
                }
                return new BsmResult(false, "配额不足,创建失败!");
            } else if (500 == e.getStatus()) {
                if (null != result) {
                    return new BsmResult(true, detail(result.getId()).getData(), "创建失败");
                }
                return new BsmResult(false, "有相同名称的镜像，创建失败!");
            } else if (400 == e.getStatus()) {
                if (null != result) {
                    return new BsmResult(true, detail(result.getId()).getData(), "创建失败");
                }
                return new BsmResult(false, "规格的磁盘大小小于镜像的磁盘大小。创建失败!");
            }
            return new BsmResult(false, "创建失败！");
        }
        if (null == result) {
            return new BsmResult(false, "创建失败！");
        } else if (null == result.getStatus()) {
            return new BsmResult(true, detail(result.getId()).getData(), "创建虚拟机状态异常！");
        } else {
        }
        return new BsmResult(true, detail(result.getId()).getData(), "创建成功！");
    }

    @Override
    public BsmResult start(String instanceId) {
        ActionResponse response = this.getClient().compute().servers().action(instanceId, Action.START);
        if (response.isSuccess()) {
            return new BsmResult(true, "启动成功！");
        } else {
            logger.error("start instance [{}] failed :{}", instanceId, response.getFault());
            return new BsmResult(false, "启动失败！");
        }
    }

    @Override
    public BsmResult stop(String instanceId) {
        ActionResponse response = this.getClient().compute().servers().action(instanceId, Action.STOP);
        if (response.isSuccess()) {
            return new BsmResult(true, "关机成功！");
        } else {
            logger.error("stop instance [{}] failed :{}", instanceId, response.getFault());
            return new BsmResult(false, "关机失败！");
        }
    }

    @Override
    public BsmResult reboot(String instanceId) {
        ActionResponse response = this.getClient().compute().servers().reboot(instanceId, RebootType.HARD);
        if (response.isSuccess()) {
            return new BsmResult(true, "重启成功！");
        } else {
            logger.error("reboot instance [{}] failed :{}", instanceId, response.getFault());
            return new BsmResult(false, "重启失败！");
        }
    }

    @Override
    public BsmResult remove(String instanceId) {
        ActionResponse response = this.getClient().compute().servers().action(instanceId, Action.FORCEDELETE);
        if (response.isSuccess()) {
            return new BsmResult(true, "删除成功！");
        } else {
            logger.error("remove instance [{}] failed :{}", instanceId, response.getFault());
            return new BsmResult(false, "删除失败！");
        }
    }

    @Override
    public BsmResult list() {
        List<ServerModel> models = Lists.newArrayList();
        List<? extends Server> servers = Lists.newArrayList();
        servers = this.getClient().compute().servers().listAll(true);
        if (null != servers) {
            for (Server server : servers) {
                BeanConvert<ServerModel, Server> convertServer = new ConvertServer();
                models.add(convertServer.convertModel(server));
            }
        }
        return new BsmResult(true, models, "success");
    }

    @Override
    public BsmResult detail(String serverId) {
        BeanConvert<ServerModel, Server> convertServer = new ConvertServer();
        Server server = null;
        Boolean flag = true;
        Long startTime = System.currentTimeMillis();

        while (flag) {
            server = this.getClient().compute().servers().get(serverId);
            if (!("BUILD".equalsIgnoreCase(server.getStatus().name())
                    || "MIGRATING".equalsIgnoreCase(server.getStatus().name()))) {
                flag = false;
            }
            Long endTime = System.currentTimeMillis();
            if (endTime - startTime > 60 * 1000) {// 等待30s
                flag = false;
            }
        }
        return new BsmResult(true, convertServer.convertModel(server), "success");
    }

    @Override
    public BsmResult joinSGroup(String serverId, String groupId) {
        ActionResponse response = this.getClient().compute().servers().addSecurityGroup(serverId, groupId);
        if (response.isSuccess()) {
            return new BsmResult(true, "操作成功！");
        } else {
            logger.error("joinSGroup [{}] failed :{}", serverId, response.getFault());
            return new BsmResult(false, "操作失败！");
        }
    }

    @Override
    public BsmResult leaveSGroup(String serverId, String groupId) {
        ActionResponse response = this.getClient().compute().servers().removeSecurityGroup(serverId, groupId);
        if (response.isSuccess()) {
            return new BsmResult(true, "操作成功！");
        } else {
            logger.error("joinSGroup [{}] failed :{}", serverId, response.getFault());
            return new BsmResult(false, "操作失败！");
        }
    }

    @Override
    public BsmResult modify(ServerModel server) {
        ServerUpdateOptions options = new ServerUpdateOptions();
        options.name(server.getName());
        Server response = this.getClient().compute().servers().update(server.getInstanceId(), options);
        if (null != response) {
            BeanConvert<ServerModel, Server> convertServer = new ConvertServer();
            return new BsmResult(true, convertServer.convertModel(response), "操作成功！");
        } else {
            logger.error("joinSGroup [{}] failed!", server.getInstanceId());
            return new BsmResult(false, "操作失败！");
        }
    }

    @Override
    public BsmResult migrate(ServerModel server) {
        String serverId = server.getInstanceId();
        ActionResponse response = this.getClient().compute().servers().migrateServer(serverId);
        if (response.isSuccess()) {
            return new BsmResult(true, "操作成功！");
        } else {
            logger.error("migrate [{}] failed :{}", serverId, response.getFault());
            return new BsmResult(false, "操作失败！");
        }
    }

    @Override
    public BsmResult OSMigrate(OSMigrateModel OSMigrate) {
        String serverId = OSMigrate.getInstanceId();
        if (!this.accessable()) {
            logger.error(this.getError());
            return new BsmResult(false, this.getError());
        }
        ActionResponse response = null;
        if (OSMigrate.getLive()) {
            response = this.getClient().compute().servers().liveMigrate(serverId,
                    LiveMigrateOptions.create().host(OSMigrate.getHost()).blockMigration(OSMigrate.getBlockMigration())
                            .diskOverCommit(OSMigrate.getDiskOverCommit()));
        } else {
            response = this.getClient().compute().servers().migrateServer(serverId);
        }
        if (response.isSuccess()) {
            return new BsmResult(true, detailMigrate(serverId).getData(), "操作成功！");
        } else {
            logger.error("migrate [{}] failed :{}", serverId, response.getFault());
            return new BsmResult(false, response.getFault());
        }
    }

    public BsmResult detailMigrate(String serverId) {
        BeanConvert<ServerModel, Server> convertServer = new ConvertServer();
        Server server = null;
        Boolean flag = true;
        Long startTime = System.currentTimeMillis();

        while (flag) {
            server = this.getClient().compute().servers().get(serverId);
            if (!"MIGRATING".equalsIgnoreCase(server.getStatus().name())) {
                flag = false;
            }
            Long endTime = System.currentTimeMillis();
            if (endTime - startTime > 60 * 1000 * 30) {// 等待30m
                flag = false;
            }
        }
        return new BsmResult(true, convertServer.convertModel(server), "success");
    }

    @Override
    public BsmResult snapshot(SnapshotModel snapshotModel) {
        try {
            String imageId = this.getClient().compute().servers().createSnapshot(snapshotModel.getInstanceId(),
                    snapshotModel.getName());
            if (null != imageId) {
                Image image = null;
                boolean flag = true;
                Date start = new Date();
                while (flag) {
                    image = this.getClient().images().get(imageId);
                    if (null != image) {
                        if (image.getStatus().name().equals("ACTIVE")) {
                            flag = false;
                        }
                    }
                    Date end = new Date();
                    if (end.getTime() - start.getTime() > 1000 * 60 * 5) {
                        flag = false;
                    }
                }
                BeanConvert<ImageModel, Image> convertImage = new ConvertImage();
                return new BsmResult(true, convertImage.convertModel(image), "备份镜像成功！");
            }
            return new BsmResult(false, "备份镜像失败！");
        } catch (ClientResponseException e) {
            logger.error("备份镜像失败！", e);
            if (409 == e.getStatus()) {
                return new BsmResult(false, "备份镜像状态冲突！");
            }
            return new BsmResult(false, "备份镜像失败！");
        }
    }

    @Override
    public BsmResult suspend(String instanceId) {
        return null;
    }

    @Override
    public BsmResult VncConsole(String vncType, String serverId) {
        try {
            VNCConsole vncConsole = this.getClient().compute().servers().getVNCConsole(serverId, Type.value(vncType));
            return new BsmResult(true, vncConsole, "访问成功");
        } catch (Exception e) {
            logger.error("vncConsole Exception", e);
            return new BsmResult(false, "访问失败");
        }
    }

    @Override
    public BsmResult resume(String instanceId) {
        try {
            ActionResponse response = this.getClient().compute().servers().action(instanceId, Action.RESUME);
            if (response.isSuccess()) {
                return new BsmResult(true, "恢复成功！");
            } else {
                logger.error("resume instance [{}] failed :{}", instanceId, response.getFault());
                return new BsmResult(false, "恢复失败！");
            }
        } catch (ClientResponseException e) {
            logger.error("resume instance [{}] failed :{}", instanceId, e);
            return new BsmResult(false, "恢复失败！");
        }

    }

    @Override
    public BsmResult unpause(String instanceId) {
        try {
            ActionResponse response = this.getClient().compute().servers().action(instanceId, Action.UNPAUSE);
            if (response.isSuccess()) {
                return new BsmResult(true, "恢复成功！");
            } else {
                logger.error("resume instance [{}] failed :{}", instanceId, response.getFault());
                return new BsmResult(false, "恢复失败！");
            }
        } catch (ClientResponseException e) {
            logger.error("resume instance [{}] failed :{}", instanceId, e);
            return new BsmResult(false, "恢复失败！");
        }

    }

}
